using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Universe.Threading.Generate
{
    class Generator
    {
        private static readonly string[] Types = "Int32 Int64 Int16 Decimal Double Single".Split();

        static void Main(string[] args)
        {
            Build1(Class, "Class.cs");
            Build1(Forward, "Forward.cs");
            Build1(Back, "Back.cs");
            Build1(Any, "Any.cs");
            Build1(Create, "Create.cs");

            Build2(Test, "RangeFor_Test{0}.cs");
        }

        private static void Build2(string content, string nameFormat)
        {
            foreach (string type in Types)
            {
                Save(string.Format(nameFormat, type), content.Replace("Int16", type));
            }
        }

        private static void Build1(string snippet, string name)
        {
            StringBuilder ret1 = new StringBuilder();
            foreach (string type in Types)
                ret1.Append(snippet.Replace("Int16", type));

            Save(name, ret1.ToString());
        }

        static void Save(string name, string content)
        {
            using(FileStream fs = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read))
            using(StreamWriter wr = new StreamWriter(fs, Encoding.ASCII))
            {
                wr.WriteLine(content);
            }
        }

        private static string Forward = @"
            if (TheKind == Kind.Int16)
                return (IEnumerable<T>)new RangeEnumerable_Int16((Int16)(ValueType)from, (Int16)(ValueType)to, 1);
";

        private static string Back = @"
            if (TheKind == Kind.Int16)
                return (IEnumerable<T>)new RangeEnumerable_Int16((Int16)(ValueType)high, (Int16)(ValueType)low, -1);
";

        private static string Create = @"
            if (TheKind == Kind.Int16)
                return (IEnumerable<T>)new RangeEnumerable_Int16((Int16)(ValueType)from, (Int16)(ValueType)to, (Int16)(ValueType)step);
";

        private static string Any = @"
            if (TheKind == Kind.Int16)
                return (IEnumerable<T>)RangeEnumerable_Int16.AnyDirection((Int16)(ValueType)start, (Int16)(ValueType)end);
";


        private static string Class = @"
    internal class RangeEnumerable_Int16 : IEnumerable<Int16>
    {
        private readonly Int16 _from;
        private readonly Int16 _to;
        private readonly Int16 _step;

        internal RangeEnumerable_Int16(Int16 from, Int16 to, Int16 step)
        {
            if (step == 0)
                throw new ArgumentException(""Zero Step of RangeFor is invalid"", ""step"");

            _from = from;
            _to = to;
            _step = step;

        }

        internal static RangeEnumerable_Int16 AnyDirection(Int16 start, Int16 end)
        {
            Int16 step = (Int16)(start > end ? -1 : 1);
            return new RangeEnumerable_Int16(start, end, step);
        }

        public IEnumerator<Int16> GetEnumerator()
        {
            return new RangeEnumerator_Int16(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RangeEnumerator_Int16(this);
        }

        struct RangeEnumerator_Int16 : IEnumerator<Int16>
        {
            private bool _isFirst;
            private Int16 _current;

            private readonly RangeEnumerable_Int16 _range;

            public RangeEnumerator_Int16(RangeEnumerable_Int16 range)
            {
                _range = range;
                _current = _range._from;
                _isFirst = true;

            }

            public Int16 Current
            {
                get
                {
                    return _current;
                }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (_isFirst)
                {
                    _isFirst = false;
                    bool has = _range._step > 0 ? _current <= _range._to : _current >= _range._to;
                    return has;
                }

                if (OverflowTest.HasOverflow(_current, _range._step))
                    return false;

                Int16 tryNext = (Int16) (_current + _range._step);
                bool isDone = _range._step > 0 ? tryNext > _range._to : tryNext < _range._to;

                if (isDone)
                    return false;
                else
                {
                    _current = tryNext;
                    return true;
                }
            }

            void IEnumerator.Reset()
            {
                _current = _range._from;
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }
        }
    }
";

        private static string Test = @"
using System;
using NUnit.Framework;

namespace Universe.Parallel.Test
{
    [TestFixture]
    public class RangeFor_TestInt16
    {

        [Test]
        public void TestBack()
        {
            Util.IsEquals(new Int16[] { 5, 4, 3, 2, 1 }, RangeFor<Int16>.Back(5, 1), ""RangeFor<Int16>.Back(5, 1)"");
            Util.IsEquals(new Int16[] { 1 }, RangeFor<Int16>.Back(1, 1), ""RangeFor<Int16>.Back(1, 1)"");
            Util.IsEquals(new Int16[] { }, RangeFor<Int16>.Back(1, 5), ""RangeFor<Int16>.Back(1, 5)"");
            Util.IsEquals(new Int16[] { Int16.MaxValue, }, RangeFor<Int16>.Back(Int16.MaxValue, Int16.MaxValue), ""RangeFor<Int16>.Back(Int16.MaxValue, Int16.MaxValue)"");
            Util.IsEquals(new Int16[] { Int16.MinValue, }, RangeFor<Int16>.Back(Int16.MinValue, Int16.MinValue), ""RangeFor<Int16>.Back(Int16.MinValue, Int16.MinValue)"");
        }

        [Test]
        public void TestCreate()
        {
            Util.IsEquals(new Int16[] { Int16.MinValue + 3, Int16.MinValue + 1 }, RangeFor<Int16>.Create(Int16.MinValue + 3, Int16.MinValue, -2), ""RangeFor<Int16>.Create(Int16.MinValue + 3, Int16.MinValue, -2)"");
            Util.IsEquals(new Int16[] { Int16.MaxValue - 3, Int16.MaxValue - 1 }, RangeFor<Int16>.Create(Int16.MaxValue - 3, Int16.MaxValue, 2), ""RangeFor<Int16>.Create(Int16.MaxValue - 3, Int16.MaxValue, 2)"");
            Util.IsEquals(new Int16[] { 1 }, RangeFor<Int16>.Create(1, 2, 3), ""RangeFor<Int16>.Create(1, 2, 3)"");
            Util.IsEquals(new Int16[] { }, RangeFor<Int16>.Create(Int16.MaxValue, Int16.MinValue, 1), ""RangeFor<Int16>.Create(Int16.MaxValue, Int16.MinValue, 1)"");
            Util.IsEquals(new Int16[] { }, RangeFor<Int16>.Create(Int16.MinValue, Int16.MaxValue, -1), ""RangeFor<Int16>.Create(Int16.MinValue, Int16.MaxValue, -1)"");
            Util.IsEquals(new Int16[] { Int16.MaxValue }, RangeFor<Int16>.Create(Int16.MaxValue, Int16.MaxValue, 1), ""RangeFor<Int16>.Create(Int16.MaxValue, Int16.MaxValue, 1)"");
            Util.IsEquals(new Int16[] { Int16.MinValue }, RangeFor<Int16>.Create(Int16.MinValue, Int16.MinValue, -1), ""RangeFor<Int16>.Create(Int16.MinValue, Int16.MinValue, -1)"");
        }

        [Test]
        public void TestForward()
        {
            Util.IsEquals(new Int16[] { 1 }, RangeFor<Int16>.Forward(1, 1), ""RangeFor<Int16>.Forward(1, 1)"");
            Util.IsEquals(new Int16[] { 1, 2, 3, 4, 5 }, RangeFor<Int16>.Forward(1, 5), ""RangeFor<Int16>.Forward(1, 5)"");
            Util.IsEquals(new Int16[] { }, RangeFor<Int16>.Forward(5, 1), ""RangeFor<Int16>.Forward(5, 1)"");
            Util.IsEquals(new Int16[] { Int16.MaxValue }, RangeFor<Int16>.Forward(Int16.MaxValue, Int16.MaxValue), ""RangeFor<Int16>.Forward(Int16.MaxValue, Int16.MaxValue)"");
            Util.IsEquals(new Int16[] { Int16.MinValue }, RangeFor<Int16>.Forward(Int16.MinValue, Int16.MinValue), ""RangeFor<Int16>.Forward(Int16.MinValue, Int16.MinValue)"");
        }

    }
}
";
    }
}
